using System;

namespace ZFramework
{
    public struct AABBI(Vec3I position, Vec3I size)
    {
        public Vec3I position = position;
        public Vec3I size = size;

        public int X
        {
            readonly get => position.x;
            set => position.x = value;
        }

        public int Y
        {
            readonly get => position.y;
            set => position.y = value;
        }

        public int Z
        {
            readonly get => position.z;
            set => position.z = value;
        }

        public int Width
        {
            readonly get => size.x;
            set => size.x = value;
        }

        public int Height
        {
            readonly get => size.y;
            set => size.y = value;
        }

        public int Length
        {
            readonly get => size.y;
            set => size.y = value;
        }

        public Vec3I End
        {
            readonly get => position + size;
            set => size = value - position;
        }

        public AABBI(int x, int y, int z, int width, int height, int length) : this(new(x, y, z), new(width, height, length)) { }

        public AABBI(Vec3I position, int width, int height, int length) : this(position, new(width, height, length)) { }

        public AABBI(int x, int y, int z, Vec3I size) : this(new(x, y, z), size) { }

        public void Set(AABBI aabb)
        {
            position = aabb.position;
            size = aabb.size;
        }


        public readonly bool Includes(Vec3I point)
        {
            if (point.x < X || point.x > X + Width) return false;
            if (point.y < Y || point.y > Y + Height) return false;
            if (point.z < Z || point.z > Z + Length) return false;
            return true;
        }

        public readonly bool Includes(Vec3 point, float unit) => Includes((point / unit).FloorToInt());
        public readonly bool Includes(int x, int y, int z) => Includes(new(x, y, z));

        public readonly AABBI Abs()
        {
            var end = End;
            return new(Math.Min(X, end.x), Math.Min(Y, end.y), Math.Min(Z, end.z), size.Abs());
        }

        public void AbsAssign() => Set(Abs());
    }
}